#ifdef KPEXT_DEV_MAIN

//#include "kpextCommonDef.h"
#include "KpExtGP.h"
#include "kpextVkContext.h"
#include "kpextBaseCompute.h"
//#include "nlohmann/json.hpp"

using namespace std;


static const unsigned int spirv_demo[] =
{
 0x07230203, 0x00010000, 0x0008000a, 0x00000042, 0x00000000, 0x00020011, 0x00000001, 0x0006000b,
0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001,
0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, 0x00000000, 0x0000000b, 0x00060010, 0x00000004,
0x00000011, 0x00000001, 0x00000001, 0x00000001, 0x00030003, 0x00000002, 0x000001c2, 0x00040005,
0x00000004, 0x6e69616d, 0x00000000, 0x00040005, 0x00000008, 0x65646e69, 0x00000078, 0x00080005,
0x0000000b, 0x475f6c67, 0x61626f6c, 0x766e496c, 0x7461636f, 0x496e6f69, 0x00000044, 0x00050005,
0x00000011, 0x5f667562, 0x5f74756f, 0x00000061, 0x00050006, 0x00000011, 0x00000000, 0x5f74756f,
0x00000061, 0x00030005, 0x00000013, 0x00000000, 0x00050005, 0x00000019, 0x5f667562, 0x615f6e69,
0x00000000, 0x00050006, 0x00000019, 0x00000000, 0x615f6e69, 0x00000000, 0x00030005, 0x0000001b,
0x00000000, 0x00050005, 0x00000021, 0x5f667562, 0x625f6e69, 0x00000000, 0x00050006, 0x00000021,
0x00000000, 0x625f6e69, 0x00000000, 0x00030005, 0x00000023, 0x00000000, 0x00050005, 0x0000002f,
0x5f667562, 0x5f74756f, 0x00000062, 0x00050006, 0x0000002f, 0x00000000, 0x5f74756f, 0x00000062,
0x00030005, 0x00000031, 0x00000000, 0x00050005, 0x00000033, 0x736e6f63, 0x6e6f5f74, 0x00000065,
0x00060005, 0x00000034, 0x68737550, 0x736e6f43, 0x746e6174, 0x00000073, 0x00040006, 0x00000034,
0x00000000, 0x006c6176, 0x00050005, 0x00000036, 0x68737570, 0x6e6f635f, 0x00007473, 0x00040047,
0x0000000b, 0x0000000b, 0x0000001c, 0x00040047, 0x00000010, 0x00000006, 0x00000004, 0x00050048,
0x00000011, 0x00000000, 0x00000023, 0x00000000, 0x00030047, 0x00000011, 0x00000003, 0x00040047,
0x00000013, 0x00000022, 0x00000000, 0x00040047, 0x00000013, 0x00000021, 0x00000002, 0x00040047,
0x00000018, 0x00000006, 0x00000004, 0x00050048, 0x00000019, 0x00000000, 0x00000023, 0x00000000,
0x00030047, 0x00000019, 0x00000003, 0x00040047, 0x0000001b, 0x00000022, 0x00000000, 0x00040047,
0x0000001b, 0x00000021, 0x00000000, 0x00040047, 0x00000020, 0x00000006, 0x00000004, 0x00050048,
0x00000021, 0x00000000, 0x00000023, 0x00000000, 0x00030047, 0x00000021, 0x00000003, 0x00040047,
0x00000023, 0x00000022, 0x00000000, 0x00040047, 0x00000023, 0x00000021, 0x00000001, 0x00040047,
0x0000002e, 0x00000006, 0x00000004, 0x00050048, 0x0000002f, 0x00000000, 0x00000023, 0x00000000,
0x00030047, 0x0000002f, 0x00000003, 0x00040047, 0x00000031, 0x00000022, 0x00000000, 0x00040047,
0x00000031, 0x00000021, 0x00000003, 0x00040047, 0x00000033, 0x00000001, 0x00000000, 0x00050048,
0x00000034, 0x00000000, 0x00000023, 0x00000000, 0x00030047, 0x00000034, 0x00000002, 0x00040047,
0x00000041, 0x0000000b, 0x00000019, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002,
0x00040015, 0x00000006, 0x00000020, 0x00000000, 0x00040020, 0x00000007, 0x00000007, 0x00000006,
0x00040017, 0x00000009, 0x00000006, 0x00000003, 0x00040020, 0x0000000a, 0x00000001, 0x00000009,
0x0004003b, 0x0000000a, 0x0000000b, 0x00000001, 0x0004002b, 0x00000006, 0x0000000c, 0x00000000,
0x00040020, 0x0000000d, 0x00000001, 0x00000006, 0x0003001d, 0x00000010, 0x00000006, 0x0003001e,
0x00000011, 0x00000010, 0x00040020, 0x00000012, 0x00000002, 0x00000011, 0x0004003b, 0x00000012,
0x00000013, 0x00000002, 0x00040015, 0x00000014, 0x00000020, 0x00000001, 0x0004002b, 0x00000014,
0x00000015, 0x00000000, 0x00030016, 0x00000017, 0x00000020, 0x0003001d, 0x00000018, 0x00000017,
0x0003001e, 0x00000019, 0x00000018, 0x00040020, 0x0000001a, 0x00000002, 0x00000019, 0x0004003b,
0x0000001a, 0x0000001b, 0x00000002, 0x00040020, 0x0000001d, 0x00000002, 0x00000017, 0x0003001d,
0x00000020, 0x00000017, 0x0003001e, 0x00000021, 0x00000020, 0x00040020, 0x00000022, 0x00000002,
0x00000021, 0x0004003b, 0x00000022, 0x00000023, 0x00000002, 0x00040020, 0x00000029, 0x00000002,
0x00000006, 0x0003001d, 0x0000002e, 0x00000006, 0x0003001e, 0x0000002f, 0x0000002e, 0x00040020,
0x00000030, 0x00000002, 0x0000002f, 0x0004003b, 0x00000030, 0x00000031, 0x00000002, 0x00040032,
0x00000017, 0x00000033, 0x00000000, 0x0003001e, 0x00000034, 0x00000017, 0x00040020, 0x00000035,
0x00000009, 0x00000034, 0x0004003b, 0x00000035, 0x00000036, 0x00000009, 0x00040020, 0x00000037,
0x00000009, 0x00000017, 0x0004002b, 0x00000006, 0x00000040, 0x00000001, 0x0006002c, 0x00000009,
0x00000041, 0x00000040, 0x00000040, 0x00000040, 0x00050036, 0x00000002, 0x00000004, 0x00000000,
0x00000003, 0x000200f8, 0x00000005, 0x0004003b, 0x00000007, 0x00000008, 0x00000007, 0x00050041,
0x0000000d, 0x0000000e, 0x0000000b, 0x0000000c, 0x0004003d, 0x00000006, 0x0000000f, 0x0000000e,
0x0003003e, 0x00000008, 0x0000000f, 0x0004003d, 0x00000006, 0x00000016, 0x00000008, 0x0004003d,
0x00000006, 0x0000001c, 0x00000008, 0x00060041, 0x0000001d, 0x0000001e, 0x0000001b, 0x00000015,
0x0000001c, 0x0004003d, 0x00000017, 0x0000001f, 0x0000001e, 0x0004003d, 0x00000006, 0x00000024,
0x00000008, 0x00060041, 0x0000001d, 0x00000025, 0x00000023, 0x00000015, 0x00000024, 0x0004003d,
0x00000017, 0x00000026, 0x00000025, 0x00050085, 0x00000017, 0x00000027, 0x0000001f, 0x00000026,
0x0004006d, 0x00000006, 0x00000028, 0x00000027, 0x00060041, 0x00000029, 0x0000002a, 0x00000013,
0x00000015, 0x00000016, 0x0004003d, 0x00000006, 0x0000002b, 0x0000002a, 0x00050080, 0x00000006,
0x0000002c, 0x0000002b, 0x00000028, 0x00060041, 0x00000029, 0x0000002d, 0x00000013, 0x00000015,
0x00000016, 0x0003003e, 0x0000002d, 0x0000002c, 0x0004003d, 0x00000006, 0x00000032, 0x00000008,
0x00050041, 0x00000037, 0x00000038, 0x00000036, 0x00000015, 0x0004003d, 0x00000017, 0x00000039,
0x00000038, 0x00050085, 0x00000017, 0x0000003a, 0x00000033, 0x00000039, 0x0004006d, 0x00000006,
0x0000003b, 0x0000003a, 0x00060041, 0x00000029, 0x0000003c, 0x00000031, 0x00000015, 0x00000032,
0x0004003d, 0x00000006, 0x0000003d, 0x0000003c, 0x00050080, 0x00000006, 0x0000003e, 0x0000003d,
0x0000003b, 0x00060041, 0x00000029, 0x0000003f, 0x00000031, 0x00000015, 0x00000032, 0x0003003e,
0x0000003f, 0x0000003e, 0x000100fd, 0x00010038,  };

void msleep(int ms){
    using  chronoms = std::chrono::milliseconds;
    std::this_thread::sleep_for(
                chronoms(ms)
                );
}


void tempTest();
void tempTestMem();


int main(){

#ifdef OS_WIN
    kpextSetWinConsoleVT100(true);
#endif

//    kpextSetLogger(nullptr, 2, 2);
    kpextSetLogger("kpextlib", 5, 2);
    kpextSetLogger(nullptr, 2, 2);

//    kpextSetLoggerLevel(KpExtLOG_LEVEL_DEBUG);
    kpextSetLoggerLevel(KpExtLOG_LEVEL_INFO);
    kpextSetLoggerPattern("[%D %H:%M:%S.%e] [%^%l%$] %v");
    SPDLOG_INFO("Hello kpextlib !");

    kpextSetVKValidationLayerEn(true);

    if(false){
        kpextSetVKPhyDeviceIndex(0);
//        kpextSetVKPhyDeviceReqPUUID(nullptr);

    }

    if(false){
        unsigned int indices[] = {
            1,2,3,4,5,
            1,2,3,4,5,
            1,2,3,4,5,
            1,2,3,4,5,
            1,2,3,4,5,
            0,1,2,3,4,5,
            0,1,2,3,4,5,
            0,1,2,3,4,5,
        };
        kpextSetVKQueueFamilyIndices(
                    indices,
                    sizeof (indices) / sizeof (decltype (indices[0]))
                );
    }

    const char extensions[] = {
        "VK_EXT_shader_atomic_float" ","
        "VK_INVALID_TEST0" ","
        "VK_INVALID_TEST1" ","
        "VK_INVALID_TEST2"
        ""
    };

    kpextSetVKDeviceReqExtensions(extensions);

    kpextInit();

    struct ttt{
        float a = 333;
        double b = 1.555;
        uint32_t c = 2;
    }ttt1;

    kpext::PipelineConstSZ scon(sizeof (ttt1),
                                      &ttt1,
                                      {&ttt1.c, &ttt1.a, &ttt1.b},
                                      {sizeof(ttt1.c), sizeof(ttt1.a), sizeof(ttt1.b)}
                                      );
    auto a = scon.data<double>(8);
    a = scon.item<float>(-2);
    a = scon.itemUint(0);


    kpext::PipelineConstSZ scon1(6);
    a = scon1.item<float>(0);
    scon1.set({1,2,3});
    scon1.set(std::vector<float>{1,2,3});

    tempTestMem();

    if(false){
        //    tempTest();
        std::thread t1(tempTestMem);
        std::thread t2(tempTestMem);

        t1.join();
        t2.join();
    }

    kpextRelease();
#ifndef KPEXT_NO_SPDLOG
    spdlog::drop_all();
#endif
}

void tempTestMem(){
    struct : public kpext::BaseCompute{
        void init(kpextVkContext * ctx){
            m_vkCtx = ctx;
        }

        void setPushConsts(float v){
            m_pipeline->m_pushConsts->set({v});
        }
    } demotest;
    demotest.init(GvkContextPtr);

    auto inputA = GvkContextPtr->stagingBuf(3 * 4);
    auto inputB = GvkContextPtr->stagingBuf(3 * 4);
    auto & outputA = inputA;
    auto & outputB = inputB;
    std::vector<std::shared_ptr<kpext::BaseBuffer>> devbufs;
    devbufs.resize(4);
    for (auto & b : devbufs) {
        b = GvkContextPtr->deviceBuf(3 * 4);
    }
    uint32_t f[1];
    *reinterpret_cast<float *>(f) = 2.0f;
    demotest.rebuild({std::begin(spirv_demo),
                      std::end(spirv_demo)},
                     devbufs,
                     {f,f+1},
                     {std::begin(f),std::end(f)},
                     {3,1,1}
                     );
    {
        auto ptr = inputA->data<float>();
        ptr[0] = 2;ptr[1] = 2;ptr[2] = 2;
        inputA->unmap();

        ptr = inputB->data<float>();
        ptr[0] = 1;ptr[1] = 2;ptr[2] = 3;
        inputB->unmap();
    }

    kpext::CmdBaseBufferCpy bufcpy;
    kpext::CmdBaseBufferSet bufset;
    kpext::CmdMemoryBarrier barrier;
    kpext::CmdBuffersMemBarrier barrierTx;
    kpext::CmdBuffersMemBarrier barrierRx;
    barrier.prepare(vk::PipelineStageFlagBits::eComputeShader,
                    vk::PipelineStageFlagBits::eComputeShader,
                    vk::AccessFlagBits::eShaderWrite,
                    vk::AccessFlagBits::eShaderRead);

    barrierTx.prepare(
                {inputA, inputB},
                vk::PipelineStageFlagBits::eTransfer,
                vk::PipelineStageFlagBits::eComputeShader,
                vk::AccessFlagBits::eTransferWrite,
                vk::AccessFlagBits::eShaderRead
                );
    barrierRx.prepare(
                {outputA, outputB},
                vk::PipelineStageFlagBits::eComputeShader,
                vk::PipelineStageFlagBits::eTransfer,
                vk::AccessFlagBits::eShaderWrite,
                vk::AccessFlagBits::eTransferRead
                );

    auto cmdbuf = GvkContextPtr->cmdbuf();
    cmdbuf->begin();
    bufcpy.prepare(devbufs[0], inputA);
    cmdbuf->record(&bufcpy);
    bufcpy.prepare(devbufs[1], inputB);
    cmdbuf->record(&bufcpy);

    cmdbuf->record(&barrierTx);
    cmdbuf->record(&demotest);
    cmdbuf->record(&barrier);
    demotest.setPushConsts(3.0f);
    cmdbuf->record(&demotest);
    cmdbuf->record(&barrierRx);

    bufcpy.prepare(outputA, devbufs[2]);
    cmdbuf->record(&bufcpy);
    bufcpy.prepare(outputB, devbufs[3]);
    cmdbuf->record(&bufcpy);
    //bufset.prepare(outputB, ~0U);
    //cmdbuf->record(&bufset);
    cmdbuf->end();
    cmdbuf->submit();
    cmdbuf->waitExec();

    auto && ret1 = outputA->vector<uint32_t>();
    auto && ret2 = outputB->vector<uint32_t>();
    // Prints the first output which is: { 4, 8, 12 }
    // Prints the second output which is: { 10, 10, 10 }
    SPDLOG_INFO("tempTestMem---\n OutA: {}", ret1);
    SPDLOG_INFO("tempTestMem---\n OutB: {}", ret2);
}

#endif // KPEXT_DEV_MAIN
